#pragma once

#include "Protocol.hpp"
#include "TcpSocket.hpp"
#include "Log.hpp"
#include "UnCopy.hpp"
#include "commen.hpp"

const uint16_t default_port = 9090;
const std::string default_ip = "127.0.0.1";
const std::string operations = "+-*/%";

class DlpClient : public UnCopy
{
public:
    DlpClient(std::string server_ip = default_ip, uint16_t server_port = default_port)
        : _server_ip(server_ip), _server_port(server_port)
    {
        init();
    }

    void init()
    {
        _socket = new TcpSocket();
        _socket->createConnectSocket(_server_ip, _server_port);
        factory = std::make_unique<DLP::ReqRespFactory>();
    }

    void start()
    {
        while(true)
        {
            std::string contentByteStream;
            std::cout << ">> ";
            std::getline(std::cin, contentByteStream);
            std::string dlpRequest = makeDlpRequest(contentByteStream); //序列化
            if(dlpRequest == "") 
            {
                std::cout << "usage: int opreation int, example: 1+1" << std::endl;
                continue;
            }
            ssize_t req_n = write(_socket->getSocketFd(), dlpRequest.c_str(), dlpRequest.size());
            if(req_n == 0)
            {
                break;
            }
            else if(req_n < 0)
            {
                _socket->connect(_server_ip, _server_port);
            }
            else
            {
                std::string dlpResponseStream = "";
                char dlpResponseBuffer[1024];
                ssize_t resp_n = read(_socket->getSocketFd(), dlpResponseBuffer, sizeof(dlpResponseBuffer));
                if(resp_n > 0)
                {
                    // 反序列化
                    std::string content;
                    dlpResponseBuffer[resp_n] = '\0';
                    dlpResponseStream += dlpResponseBuffer;
                    while(DLP::dlpDecoding(dlpResponseStream, content))
                    {
                        std::shared_ptr<DLP::Response> resp = std::make_shared<DLP::Response>();
                        resp->deserialize(content); //if return false
                        int result = resp->getResult();
                        int code = resp->getCode();

                        if(code == -1) std::cout << "arithmetic exception" << std::endl;
                        else std::cout << "result = " << result << std::endl;
                    }
                }
            }
        }
        std::cout << "client quit..." << std::endl;
    }

    std::string makeDlpRequest(const std::string& contentByteStream)
    {
        if(contentByteStream.find(" ") != std::string::npos)
        {
            std::cout << "bad space" << std::endl;
            return "";
        }
        int operationPos = -1;
        for(int i = 0; i < operations.size(); i++)
        {
            int pos = contentByteStream.find(operations[i]);
            if(pos != std::string::npos) operationPos = pos;
        }
        if(operationPos == -1)
        {
            std::cout << "unknown operation" << std::endl;
            return "";
        }
        char op = contentByteStream[operationPos];
        int x = std::stoi(contentByteStream.substr(0, operationPos));
        int y = std::stoi(contentByteStream.substr(operationPos + 1));

        std::shared_ptr<DLP::Request> req = factory->makeRequest(x, y, op);
        return DLP::dlpEncoding(req->serialize());
    }

    ~DlpClient()
    {}
private:
    Socket* _socket;
    std::string _server_ip;
    uint16_t _server_port;
    std::unique_ptr<DLP::ReqRespFactory> factory;
};